package org.wltea.analyzer.seg;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.wltea.analyzer.Context;
import org.wltea.analyzer.Lexeme;
import org.wltea.analyzer.dic.Dictionary;
import org.wltea.analyzer.dic.Hit;
import org.wltea.analyzer.help.CharacterHelper;

public class DictMatchHandler {

	private final List<Hit> hitList;

	private final List<Lexeme> tmpLexemes;

	public DictMatchHandler() {
		hitList = new LinkedList<Hit>();
		tmpLexemes = new LinkedList<Lexeme>();
	}

	private void addTMpLexeme(Lexeme lexeme) {
		tmpLexemes.add(lexeme);
	}

	private void handleDictMatch(char[] segmentBuff, int start, int len,
			Context context, int lexemeType) {
		// System.out.println("handleDictMatch:start=" + start + ",len=" + len
		// + ",type=" + lexemeType + ",content="
		// + new String(segmentBuff, start, len) + ",contex="
		// + context.getCursor());
		boolean matched = false;
		Lexeme newLexeme = new Lexeme(context.getBuffOffset(), start, len,
				lexemeType);
		if (hitList.size() > 0) {
			// 处理词段队列
			Hit[] tmpArray = hitList.toArray(new Hit[hitList.size()]);
			int lastEnd = -1;
			for (int i = tmpArray.length - 1; i >= 0; i--) {
				Hit hit = tmpArray[i];
				int start1 = start;
				int len1 = len;
				if (start > 0 && segmentBuff[start - 1] == ' ') {
					start1 = start - 1;
					len1 = len + 1;
				}
				hit = Dictionary.matchWithHit(segmentBuff, start1, len1, hit);
				hit.addLexemeType(lexemeType);
				if (hit.isMatch()) {// 匹配成词
					// 输出当前的词
					Lexeme newLexeme1 = new Lexeme(context.getBuffOffset(),
							hit.getBegin(), hit.getEnd() - hit.getBegin() + 1,
							hit.getLexemeType());
					if (hit.isExt()) {
						newLexeme1.setInExtDict();
					} else {
						newLexeme1.setInBaseDict();
					}
					context.addLexeme(newLexeme1);
					// 避免长短词的多次切分
					if (hit.getEnd() > lastEnd) {
						if (hit.getBegin() < start) {
							addTMpLexeme(newLexeme);
						}
						lastEnd = hit.getEnd();
						processUnknown(segmentBuff, context, hit);
					}
					if (!hit.isPrefix()) {
						hitList.remove(hit);
					}
					matched = true;
				} else if (hit.isUnmatch()) {// 不匹配
					// 移出当前的hit
					hitList.remove(hit);
				}
			}
		}
		// 处理以input为开始的一个新hit
		Hit hit = Dictionary.matchInMainDict(segmentBuff, start, len);
		hit.addLexemeType(lexemeType);
		if (hit.isMatch()) {// 匹配成词
			processUnknown(segmentBuff, context, hit);
			// 输出当前的词
			if (hit.isExt()) {
				newLexeme.setInExtDict();
			} else {
				newLexeme.setInBaseDict();
			}
			newLexeme.setLexemeType(hit.getLexemeType());
			context.addLexeme(newLexeme);
			if (hit.isPrefix()) {// 同时也是前缀
				// 向词段队列增加新的Hit
				hitList.add(hit);
			}
		} else if (hit.isPrefix()) {// 前缀，未匹配成词
			hitList.add(hit);
			if (!matched) {
				addTMpLexeme(newLexeme);
			}
		} else if (hit.isUnmatch()) {
			if (lexemeType == Lexeme.TYPE_CONNECTOR
					|| (CharacterHelper.isLetterConnector(segmentBuff[start]) || segmentBuff[start
							+ len - 1] == '.')) {
				return;
			}
			if (!matched) {
				processUnknown(segmentBuff, context, hit);
				context.addLexeme(newLexeme);
			}
		}
	}

	/**
	 * mix有后缀情况
	 * 
	 * @param segmentBuff
	 * @param start
	 * @param len
	 * @param context
	 * @param lexemeType
	 */
	public void handleMixDictMatch(char[] segmentBuff, int start, int len,
			Context context, int lexemeType) {
		Hit hit = Dictionary.matchInMainDict(segmentBuff, start, len);
		if (hit.isMatch()) {// 匹配成词
			Lexeme newLexeme = new Lexeme(context.getBuffOffset(), start, len,
					lexemeType);
			if (hit.isExt()) {
				newLexeme.setInExtDict();
			} else {
				newLexeme.setInBaseDict();
			}
			newLexeme.setLexemeType(hit.getLexemeType());
			context.addLexeme(newLexeme);
		}
	}

	public void handleCJK(char[] segmentBuff, Context context) {
		handleDictMatch(segmentBuff, context.getCursor(), 1, context,
				Lexeme.TYPE_CJK_UNKNOWN);
	}

	private void processUnknown(char[] segmentBuff, Context context, Hit hit) {
		if (tmpLexemes.isEmpty()) {
			return;
		}
		int begin = hit.getBegin();
		int end = hit.getEnd();
		Iterator<Lexeme> iterator = tmpLexemes.iterator();
		while (iterator.hasNext()) {
			Lexeme lexeme = iterator.next();
			if ((lexeme.getEnd() - 1) <= begin) {
				if (lexeme.getLexemeType() != Lexeme.TYPE_CONNECTOR) {
					context.addLexeme(lexeme);
				}
				iterator.remove();
			} else {
				break;
			}
		}
		if (hit.isUnmatch() || tmpLexemes.isEmpty()) {
			return;
		}
		if (hit.getLexemeType() == Lexeme.TYPE_CJK_NORMAL) {
			if (tmpLexemes.get(0).getBegin() == begin) {
				iterator = tmpLexemes.iterator();
				while (iterator.hasNext()) {
					Lexeme lexeme = iterator.next();
					if (lexeme.getEnd() <= (end + 1)) {
						iterator.remove();
					} else {
						break;
					}
				}
			} else {
				iterator = tmpLexemes.iterator();
				while (iterator.hasNext()) {
					Lexeme lexeme = iterator.next();
					if (lexeme.getEnd() <= (end + 1)) {
						if (lexeme.getLexemeType() != Lexeme.TYPE_CONNECTOR) {
							context.addLexeme(lexeme);
						}
						iterator.remove();
					} else {
						break;
					}
				}
			}
		} else {
			iterator = tmpLexemes.iterator();
			while (iterator.hasNext()) {
				Lexeme lexeme = iterator.next();
				if (lexeme.getEnd() <= (end + 1)) {
					if (lexeme.getLexemeType() != Lexeme.TYPE_CONNECTOR) {
						context.addLexeme(lexeme);
					}
					iterator.remove();
				} else {
					break;
				}
			}
		}
	}

	public void handleSeprator(char[] segmentBuff, Context context) {
		Hit hit = new Hit();
		hit.setBegin(context.getCursor());
		hit.setEnd(context.getCursor());
		processUnknown(segmentBuff, context, hit);
		// 清空词段队列
		hitList.clear();
		tmpLexemes.clear();
	}

	public void handleMix(char[] segmentBuff, int start, Integer lenth,
			Context context, int lexemeType, boolean included) {
		if (included) {
			Lexeme newLexeme = new Lexeme(context.getBuffOffset(), start,
					lenth, lexemeType);
			context.addLexeme(newLexeme);
			return;
		}
		handleDictMatch(segmentBuff, start, lenth, context, lexemeType);
	}

	public boolean needLocked() {
		return !hitList.isEmpty() || !tmpLexemes.isEmpty();
	}

	public void reset() {
		hitList.clear();
		tmpLexemes.clear();
	}
}
